const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'

// 工具函数
function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    const result = exeFn(value)
    resolve(result)
  }catch(err){
    reject(err)
  }
}


class GYPromise{
  constructor(executor){
    this.status = PROMISE_STATUS_PENDING
    this.value = undefined
    this.reason = undefined
    this.onFulfilledFns = []
    this.onRejectedFns = []

    const resolve = (value) =>{
      if(this.status ===PROMISE_STATUS_PENDING){
        // 微任务
        queueMicrotask(() => {
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_FULFILLED
          this.value = value
          // 执行then传进来的第一个回调函数
          // 遍历
          this.onFulfilledFns.forEach(fn=>{
            fn(this.value)
          })
        });
      }
      
    }
    const reject = (reason)=>{
      if(this.status === PROMISE_STATUS_PENDING){
        queueMicrotask(()=>{
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_REJECTED
          this.reason = reason
          // 执行then传进来的第二个回调函数
          this.onRejectedFns.forEach(fn=>{
            fn(this.reason)
          })
        })
      }
    }
    try{
      executor(resolve,reject)
    }catch(err){
      reject(err)
    }
  }

  // then方法
  then(onFulfilled,onRejected){
    // onRejected = onRejected === undefined ? err => {throw err} : onRejected
    onRejected = onRejected || (err =>{throw err})

    onFulfilled = onFulfilled || (value =>{return value})

    return new GYPromise((resolve,reject)=>{
       // 1.在then调用的时候，状态已经确定下来
    if(this.status === PROMISE_STATUS_FULFILLED){
      execFunctionWithCatchError(onFulfilled,this.value,resolve,reject)
    }
    if(this.status === PROMISE_STATUS_REJECTED){
      execFunctionWithCatchError(onRejected,this.reason,resolve,reject)
    }

    // 2.将成功回调和失败回调放到数组中
    if(this.status === PROMISE_STATUS_PENDING){
      if(onFulfilled){
        this.onFulfilledFns.push(()=>{
          execFunctionWithCatchError(onFulfilled,this.value,resolve,reject)
        })
      }
      if(onRejected){
        this.onRejectedFns.push(()=>{
          execFunctionWithCatchError(onRejected,this.reason,resolve,reject)
        })
      }
    }
    })
  }

  // catch方法
  catch(onRejected){
    return this.then(undefined,onRejected)
  }

  // finally
  finally(onFinally){
    this.then(()=>{
      onFinally()
    },()=>{
      onFinally()
    })
  }

  // 类方法的实现
  static resolve(value){
    return new GYPromise((resolve)=>{
      resolve(value)
    })
  }

  static reject(reason){
    return new GYPromise((resolve,reject)=>{
      reject(reason)
    })
  }

  // all类方法
  static all(promises){
    return new GYPromise((resolve,reject)=>{
      // 收集resolve结果
      const values = []
      promises.forEach(promise =>{
        promise.then(res=>{
          values.push(res)
          if(values.length === promises.length){
            resolve(values)
          }
        },err=>{
          reject(err)
        })
      })
    })
  }

  static allSettled(promises){
    return new GYPromise((resolve)=>{
      const results = []
      promises.forEach(promise =>{
        promise.then(res=>{
          results.push({ status: PROMISE_STATUS_FULFILLED,value:res})
          if(results.length === promises.length){
            resolve(results)
          }
        },err=>{
          results.push({ status: PROMISE_STATUS_REJECTED,value:err})
          if(results.length === promises.length){
            resolve(results)
          }
        })
      })
    })
  }


  // race类方法  竞赛  谁先有结果
  static race(promises){
    return new GYPromise((resolve,reject)=>{
      promises.forEach(promise=>{
        // promise.then(res=>[
        //   resolve(res)
        // ],err=>{
        //   reject(err)
        // })
        promise.then(resolve,reject)
      })
    })
  }

  // any 至少应该resolve
  static any(promises){
    const reasons = []
    return new GYPromise((resolve,reject)=>{
      promises.forEach(promise=>{
        promise.then(resolve,err=>{
          reasons.push(err)
          if(reasons.length === promises.length){
            reject(new AggregateError(reasons))
          }
        })
      })
    })
  }

}


